package com.imooc.pan.server.modules.file.service.impl;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.imooc.pan.core.exception.RPanBusinessException;
import com.imooc.pan.core.utils.IdUtil;
import com.imooc.pan.server.common.config.PanServerConfig;
import com.imooc.pan.server.modules.file.context.FileChunkSaveContext;
import com.imooc.pan.server.modules.file.converter.FileConverter;
import com.imooc.pan.server.modules.file.entity.RPanFileChunk;
import com.imooc.pan.server.modules.file.enums.MergeFlagEnum;
import com.imooc.pan.server.modules.file.service.RPanFileChunkService;
import com.imooc.pan.server.modules.file.mapper.RPanFileChunkMapper;
import com.imooc.pan.storage.engine.core.StorageEngine;
import com.imooc.pan.storage.engine.core.context.StoreChunkFileContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.Date;
import java.util.Objects;

/**
* @author 黄怀镔
* @description 针对表【r_pan_file_chunk(文件分片信息表)】的数据库操作Service实现
* @createDate 2024-06-06 22:44:17
*/
@Service
public class RPanFileChunkServiceImpl extends ServiceImpl<RPanFileChunkMapper, RPanFileChunk> implements RPanFileChunkService{

    @Autowired
    private PanServerConfig panServerConfig;


    @Autowired
    private StorageEngine storageEngine;

    @Autowired
    private FileConverter fileConverter;

    /**
     * 保存文件分片和记录
     * 判断文件是否全部上传成功
     * @param context
     */
    @Override
    public void saveFileChunk(FileChunkSaveContext context) {
        doSaveChunkFile(context);
        doMergeChunkFile(context);
    }

    /**
     * 判断分片文件是否上传成功
     * @param context
     */
    private void doMergeChunkFile(FileChunkSaveContext context) {
        Integer count = lambdaQuery().eq(RPanFileChunk::getIdentifier, context.getIdentifier())
                .eq(RPanFileChunk::getCreateUser, context.getUserId()).count();
        //分片文件上传成功
        if(Objects.equals(count, context.getTotalChunks())){
            context.setMergeFlagEnum(MergeFlagEnum.READY);
        }
    }

    /**
     * 保存文件分片和记录
     * @param context
     */
    private void doSaveChunkFile(FileChunkSaveContext context) {
        doStoreChunkFile(context);
        doSaveRecord(context);
    }

    /**
     * 保存文件分片记录到数据库
     * @param context
     */
    private void doSaveRecord(FileChunkSaveContext context) {
        RPanFileChunk record = new RPanFileChunk();
        record.setId(IdUtil.get());
        record.setChunkNumber(context.getChunkNumber());
        record.setCreateTime(new Date());
        record.setCreateUser(context.getUserId());
        record.setExpirationTime(DateUtil.offsetDay(new Date(),panServerConfig.getChunkFileExpirationDays()));
        record.setIdentifier(context.getIdentifier());
        record.setRealPath(context.getRealPath());
        if(!save(record)){
            throw new RPanBusinessException("保存文件分片记录失败");
        }
    }

    /**
     * 委托存储引擎保存文件分片
     * @param context
     */
    private void doStoreChunkFile(FileChunkSaveContext context) {
        try{
            StoreChunkFileContext chunkFileContext = fileConverter.fileChunkSaveContextToStoreChunkFileContext(context);
            chunkFileContext.setInputStream(context.getFile().getInputStream());
            chunkFileContext.setCurrentChunkSize(context.getCurrentChunkSize());
            storageEngine.storeChunkFile(chunkFileContext);
            context.setRealPath(chunkFileContext.getRealPath());
        }catch (IOException e){
            e.printStackTrace();
            throw new RPanBusinessException("上传文件到存储引擎失败");
        }
    }
}
